#include "linger_session_map.h"

#include "base/logging.h"
#include "uid_session_map.h"
#include "rpc_thread_manager.h"
#include "update_session_task.h"
#include "create_message_task.h"
#include "notify_presence_task.h"

namespace imserver {

extern boost::asio::io_service g_io_service;

using apache::thrift::concurrency::Runnable;

static void LingerTimerCallback(const boost::system::error_code& error, int64_t uid, const std::string & session) {
  if (error) {
    return;
  }
  LOG_INFO("LingerTimerCallback, session " << session << " expired. uid=" << uid);

  UidSessionMap::Instance().Remove(uid, session);
  GetThreadManager()->add(boost::shared_ptr<Runnable>(new UpdateSessionTask(uid, session, false)));
  GetThreadManager()->add(boost::shared_ptr<Runnable>(new NotifyPresenceTask(uid, session, SessionType::OFFLINE)));
  LingerSessionMap::Instance().Expire(session);
}


LingerSession::LingerSession(int64_t uid, const std::string & session)
    : timer_(g_io_service, boost::posix_time::seconds(10)), buffered_messages_(NULL) {
}

LingerSession::~LingerSession() {
  if (buffered_messages_) {
    // TODO : 正确处理 presence 等消息类型
    for(size_t i = 0; i < buffered_messages_->size(); ++i) {
      GetThreadManager()->add(boost::shared_ptr<Runnable>(new CreateMessageTask(buffered_messages_->at(i))));
    }
    LOG_INFO("buffered_messages_ LOST fixed! size=" << buffered_messages_->size());
    delete buffered_messages_;
  }
}

void LingerSession::StartTimer(int64_t uid, const std::string & session) {
  timer_.async_wait(boost::bind(&LingerTimerCallback,
                     boost::asio::placeholders::error, uid, session));
}

void LingerSessionMap::Add(int64_t uid, const std::string & session) {
  LOG_DEBUG("uid " << uid << " session " << session << " begin linger.");
  SessionMapType::iterator it = linger_sessions_.find(session);

  if (it != linger_sessions_.end()) {
    LOG_WARN("uid " << uid << " session " << session << " already lingering.");
    return;
  }

  if (uid > 0 && !session.empty()) {
    LingerSessionPtr linger_session(new LingerSession(uid, session));
    linger_sessions_.insert(std::make_pair(session, linger_session));

    linger_session->StartTimer(uid, session);
  }
}

int LingerSessionMap::Expire(const std::string & session) {
  LOG_DEBUG("linger session " << session << " expired");
  linger_sessions_.erase(session);
  return 0;
}

ImMessageList * LingerSessionMap::Revive(const std::string & session) {
  SessionMapType::iterator it = linger_sessions_.find(session);
  if (it == linger_sessions_.end()) {
    LOG_WARN("Bad revive! session " << session << " not lingering.");
    return NULL;
  }

  it->second->CancelTimer();
  ImMessageList * buffered_messages = it->second->FetchMessages();

  linger_sessions_.erase(it);

  return buffered_messages;
}

bool LingerSessionMap::BufferMessage(const std::string & session, const ImMessage & message) {
  SessionMapType::iterator it = linger_sessions_.find(session);
  if (it == linger_sessions_.end()) {
    // TODO : 处理此种情况下的消息丢失
    LOG_WARN("linger session " << session << " doesn't exist. MESSAGE LOST!");
    return false;
  }

  LOG_DEBUG("linger session " << session << " BufferMessage ok.");
  it->second->AppendMessage(message);
  return 1;
}

}

